/*
 * Copyright 2024 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.firebase.dataconnect.generated

import com.google.firebase.dataconnect.ExperimentalFirebaseDataConnect
import com.google.firebase.dataconnect.FirebaseDataConnect

/**
 * The interface to be implemented by the over-arching "connector" classes that are generated by the
 * Firebase CLI code generation.
 *
 * ### Safe for concurrent use
 *
 * All methods and properties of [GeneratedConnector] are thread-safe and may be safely called
 * and/or accessed concurrently from multiple threads and/or coroutines.
 *
 * ### Stable for inheritance
 *
 * The [GeneratedConnector] interface _is_ stable for inheritance in third-party libraries, as new
 * methods will not be added to this interface and contracts of the existing methods will not be
 * changed, except possibly during major version number changes.
 */
public interface GeneratedConnector<T : GeneratedConnector<T>> {

  /** The [FirebaseDataConnect] instance used by this object. */
  public val dataConnect: FirebaseDataConnect

  /**
   * Creates and returns a new object that is a _copy_ of this object, but with the properties whose
   * names corresponding to the given arguments changed to the respective argument's value.
   *
   * This function is essentially the same as the `copy()` method that is generated by the Kotlin
   * compiler for `data class` classes.
   */
  @ExperimentalFirebaseDataConnect
  public fun copy(
    dataConnect: FirebaseDataConnect = this.dataConnect,
  ): T

  /**
   * Returns a list containing all [GeneratedQuery] and [GeneratedMutation] objects defined as
   * properties in this object, in an unspecified order..
   *
   * Namely, the returned list will contain exactly the elements returned from [queries] and
   * [mutations].
   *
   * @see queries
   * @see mutations
   */
  @ExperimentalFirebaseDataConnect public fun operations(): List<GeneratedOperation<T, *, *>>

  /**
   * Returns a list containing all [GeneratedQuery] objects defined as properties in this object in
   * an unspecified order.
   *
   * @see operations
   * @see mutations
   */
  @ExperimentalFirebaseDataConnect public fun queries(): List<GeneratedQuery<T, *, *>>

  /**
   * Returns a list containing all [GeneratedMutation] objects defined as properties in this object
   * in an unspecified order.
   *
   * @see operations
   * @see queries
   */
  @ExperimentalFirebaseDataConnect public fun mutations(): List<GeneratedMutation<T, *, *>>

  /**
   * Compares this object with another object for equality.
   *
   * If this methods returns `true` then invoking any method or accessing any property on `this`
   * should have the same side effects as accessing the same property or invoking the same method
   * with the same arguments on `other`, respectively. The implementation checks for _logical_
   * equality, rather than _referential_ equality. A likely implementation looks like this:
   *
   * ```
   * override fun equals(other: Any?): Boolean =
   *   other is DemoGeneratedConnectorImpl &&
   *   other.dataConnect == dataConnect
   * ```
   *
   * @param other The object to compare to this for equality.
   * @return `true` if, and only if, the given object is logically "equal" to this object.
   */
  override fun equals(other: Any?): Boolean

  /**
   * Calculates and returns the hash code for this object.
   *
   * @return the hash code for this object.
   */
  override fun hashCode(): Int

  /**
   * Returns a string representation of this object, useful for debugging.
   *
   * The string representation is _not_ guaranteed to be stable and may change without notice at any
   * time. Therefore, the only recommended usage of the returned string is debugging and/or logging.
   * Namely, parsing the returned string or storing the returned string in non-volatile storage
   * should generally be avoided in order to be robust in case that the string representation
   * changes.
   *
   * @return a string representation of this object.
   */
  override fun toString(): String
}
